package controllers

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/goravel/framework/contracts/http"
	"github.com/goravel/framework/facades"
	httpfacades "github.com/hulutech-web/http_result"
	"goravel/app/models"
	"goravel/packages/mqtt"
	"goravel/packages/mqtt/utils"
	"goravel/packages/socket/servers"
	"time"
)

type CommandController struct {
	//Dependent services
	mqttControl mqtt.MqttControl
}

type Res struct {
	Message     string `json:"message"`
	DataAddress string `json:"data_address"`
	Parameter   string `json:"parameter"`
	Value       string `json:"value"`
}

func NewCommandController() *CommandController {
	return &CommandController{
		mqttControl: mqtt.ServerClientControl,
	}
}

func (r *CommandController) Send(ctx http.Context) http.Response {

	device_id := ctx.Request().Input("device_id")
	command_id := ctx.Request().Input("command_id")
	readCmd := models.Readcmd{}
	facades.Orm().Query().Model(&models.Readcmd{}).Where("id=?", command_id).First(&readCmd)
	if readCmd.ID == 0 {
		return httpfacades.NewResult(ctx).Error(500, "命令不存在", nil)
	}
	data_address := readCmd.DataAddress
	data_parameter := readCmd.Parameter

	byte_size := readCmd.ByteSize
	if readCmd.ByteSize > 1 {
		byte_size = readCmd.ByteSize / 2
	}
	byteStr, _ := utils.BuildCommand(device_id, data_address, byte_size, data_parameter)
	businessData := models.Businessdata{
		DataType: readCmd.Parameter,
		Command:  byteStr,
		DeviceId: device_id,
		Unit:     readCmd.Unit,
	}

	facades.Orm().Query().Model(&models.Businessdata{}).Create(&businessData)
	msg := mqtt.Instruction{
		DeviceID: device_id,
		Data:     byteStr,
		ReadCmd:  readCmd,
	}

	err := r.mqttControl.PublishMessage(msg.DeviceID, msg.Data)
	if err != nil {
		return httpfacades.NewResult(ctx).Error(500, "发送失败", err.Error())
	}
	go r.waitForCompletion(msg)
	//等待数据回传

	return httpfacades.NewResult(ctx).Success("发送成功", nil)
}

func (r CommandController) waitForCompletion(msg mqtt.Instruction) {
	mqtt.ReadCmdMapChan[msg.DeviceID] = make(chan mqtt.Instruction, 1)
	//再把msg传入管道
	mqtt.ReadCmdMapChan[msg.DeviceID] <- msg
	baseCtx := context.Background()
	timeout := 20 * time.Second
	ctxWithTimeout, cancel := context.WithTimeout(baseCtx, timeout)
	defer cancel()
	fmt.Println("===========》等待《========")

	for {
		select {
		case isOk := <-mqtt.CompletionSignal:
			// 检查指令是否已完成
			if isOk {
				fmt.Println("===========》完成《========")
			} else {
				fmt.Println("===========》错误《========")
			}
			return

		case <-ctxWithTimeout.Done():
			mqtt.CompletionSignal <- false
			<-mqtt.ReadCmdMapChan[msg.DeviceID]
			fmt.Println("===========》超时《========")
			//构造命令
			res := Res{
				Message:     "命令超时，请检查设备是否在线",
				DataAddress: msg.ReadCmd.DataAddress,
				Parameter:   msg.ReadCmd.Parameter,
				Value:       "",
			}
			marshal, _ := json.Marshal(res)
			strRes := string(marshal)
			servers.SendMessage2System(msg.DeviceID, "1", 2001, "失败", strRes)
			//延时1s置空mqtt.CompletionSignal
			time.Sleep(1 * time.Second)
			mqtt.CompletionSignal = make(chan bool, 1)
			return
		}
	}
}
